// example on constructors and destructors
#include <iostream>
#include <tr1/unordered_map>
#include <string.h>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/random/mersenne_twister.hpp>
#include "boost/random.hpp"
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/taus88.hpp>
#include <boost/random/linear_congruential.hpp>
#include <unistd.h>
#include <boost/functional/hash.hpp>
#include "entry.h"
#include <time.h>
/*
 #include <boost/random/linear_congruential.hpp>

 #include <boost/random/uniform_01.hpp>
 #include <boost/random/uniform_int.hpp>


 */

using namespace std;
using namespace boost;
using namespace tr1;

#include <iostream>
//typedef boost::uniform_real<> NumberDistribution;
typedef boost::uniform_01<> NumberDistribution;
typedef boost::mt19937 RandomNumberGenerator;
typedef boost::variate_generator<RandomNumberGenerator&, NumberDistribution> RandGenerator;
int p = 2;
//NumberDistribution distribution(0, 1);
NumberDistribution distribution;
RandomNumberGenerator generator;
RandGenerator numberGenerator(generator, distribution);
void mkrandom(boost::minstd_rand &intgen) {
	boost::uniform_01 < boost::minstd_rand > gen(intgen);
	std::cout << gen() << std::endl;

	const size_t n = 5;
	for (size_t i = 0; i < n; ++i) {
		std::cout << gen() << std::endl;
	}
}

int dohash(int x, unordered_map<int, int> *h, int bit) {
	if (h->find(x) == h->end()) {
		srand(x + bit);
		float _rand = ((float) rand() / (float) ((long) RAND_MAX + 1));
		//cerr << _rand << ",";
		int _hash = (int) (_rand * (float) p);
		h->insert(make_pair<int, int>(x, _hash));
	}
	return h->find(x)->second;
}

int dohash_mt(int x, unordered_map<int, int> *h, int bit) {
	if (h->find(x) == h->end()) {
		generator.seed(x + bit);
		float rand = (float)numberGenerator();
		cerr << "r: " << rand << endl;
		int _hash = (int) (rand * (float) p);
		h->insert(make_pair<int, int>(x, _hash));
	}
	return h->find(x)->second;
}


int main() {
	clock_t start = clock();
	Entry e(1,1,10.0, 1.0);
	for (int i = 0; i < 100000000; i++) {
		hash_value(e);
	}
	clock_t ends = clock();
	cerr << "Running Time : " 	<< (double) (ends - start) / CLOCKS_PER_SEC << endl;
	start = clock();
	for (int i = 0; i < 100000000; i++) {
			e.hash;
	}
	ends = clock();
	cerr << "Running Time : " 	<< (double) (ends - start) / CLOCKS_PER_SEC << endl;
	return -1 ;

	/*	generator.seed(std::time(0));
	 std::cout << numberGenerator() << std::endl;
	 generator.seed(std::time(0));
	 std::cout << numberGenerator() << std::endl;
	 generator.seed(std::time(0));
	 std::cout << numberGenerator() << std::endl;
	 return -1;*/

	/*boost::minstd_rand intgen;
	 intgen.seed(1);
	 mkrandom(intgen);
	 intgen.seed(20001);
	 mkrandom(intgen);*/

	int length = 4;
	int dist[p];
	fill_n(dist, p, 0);
	unordered_map<int, int> count;

	for (int i = 0; i < 2; i++) {
		for (int k = 0; k < length; k++) {
			int hash = dohash_mt(k, &count, i);
			dist[hash]++;
			//(int) (((float) rand() / (float) ((long) RAND_MAX + 1)) * p);
		}
	}
	for (int i = 0; i < p; i++)
		cerr << "DIST at " << i << "\t" << dist[i] << endl;
	cerr << "**" << endl;

	count.clear();
	fill_n(dist, p,0);

	for (int i = 0; i < length; i++) {
		int hash = dohash(i, &count, 0);
		dist[hash]++;
		//(int) (((float) rand() / (float) ((long) RAND_MAX + 1)) * p);
	}
	cerr << "**" << endl;
	unordered_map<int, int> count2;
	for (int i = 0; i < length; i++) {
		int hash = dohash(i, &count2, 1);
		dist[hash]++;
		//(int) (((float) rand() / (float) ((long) RAND_MAX + 1)) * p);
	}
	for (int i = 0; i < p; i++)
		cerr << "DIST at " << i << "\t" << dist[i] << endl;
	cerr << "**" << endl;

	unordered_map<int, int>::iterator it;

	/*
	 * for (it = count.begin(); it != count.end(); it++) {
	 cerr << it->first << "\t" << it->second << endl;
	 }
	 cerr << "\n\n" << endl;

	 for (it = count2.begin(); it != count2.end(); it++) {
	 cerr << it->first << "\t" << it->second << endl;
	 }*/

	unordered_map<int, int> count3;
	for (int i = 0; i < 1000000; i++) {
		int hash = (int) (((float) rand() / (float) ((long) RAND_MAX + 1)) * p);
		if (count3.find(hash) == count3.end())
			count3.insert(make_pair(hash, 0));
		count3.find(hash)->second++;
	}
	cerr << "\n\n" << endl;

	for (it = count3.begin(); it != count3.end(); it++) {
		cerr << it->first << "\t" << it->second << endl;
	}
}
